/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.pig4cloud.pigx.contract.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.contants.SystemConfigConstants;
import com.pig4cloud.pigx.common.customize.utils.CommonUtil;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.contract.bo.ContractStatisticsBO;
import com.pig4cloud.pigx.contract.entity.ContractPosition;
import com.pig4cloud.pigx.contract.enums.ContractOrderEnum;
import com.pig4cloud.pigx.contract.mapper.ContractPositionMapper;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolMongo;
import com.pig4cloud.pigx.contract.service.ContractPositionService;
import com.pig4cloud.pigx.contract.utils.ContractUtils;
import com.pig4cloud.pigx.contract.vo.ContractPositionPageVO;
import com.pig4cloud.pigx.contract.vo.ContractPositionStatisticsWebVO;
import com.pig4cloud.pigx.contract.vo.ContractRankingVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 仓位表
 *
 * @date 2022-08-11 10:08:43
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/contractposition")
@Api(value = "contractposition", tags = "仓位表管理")
public class ContractPositionController {

	private final ContractPositionService contractPositionService;

	private final ContractPositionMapper positionMapper;

	private final MongoTemplate mongo;

	private final ContractUtils utils;

	private final RedisTemplate redis;

	/**
	 * 分页查询
	 *
	 * @param page             分页对象
	 * @param contractPosition 仓位表
	 * @return
	 */
	@ApiOperation(value = "分页查询", notes = "分页查询")
	@GetMapping("/page")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_view')")
	public R<ContractStatisticsBO<ContractPositionPageVO>> getContractPositionPage(Page<ContractPosition> page, ContractPosition contractPosition) {
		QueryWrapper<ContractPosition> query = new QueryWrapper<>();
		// 时间检索
		if (contractPosition.getCreateTime() != null) {
			String time = contractPosition.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			query.like("create_time", time);
		}
		if (contractPosition.getSymbolId() != null) {
			query.eq("symbol_id",contractPosition.getSymbolId());
		}
		if (contractPosition.getId() != null) {
			query.like("id",contractPosition.getId());
		}
		if (contractPosition.getUserId() != null) {
			query.like("user_id",contractPosition.getUserId());
		}
		if (contractPosition.getSide() != null) {
			query.eq("side",contractPosition.getSide());
		}
		query.orderByDesc("create_time");
		Page<ContractPosition> pageList = contractPositionService.page(page, query);

		List<ContractPositionPageVO> voList = new ArrayList<>();
		for (ContractPosition record : pageList.getRecords()) {
			ContractPositionPageVO vo = new ContractPositionPageVO();
			BeanUtils.copyProperties(record,vo);
			// 标记价
			String markRedisKey = vo.getSymbolName() + "_mark_price";
			Object markPrice = redis.opsForValue().get(markRedisKey);
			if (markPrice != null) {
				// 做多做空未实现营口
				if (vo.getSide().equals(ContractOrderEnum.Side.MORE.getName())) {
					vo.setFloatProfit(
							(new BigDecimal(markPrice.toString()).subtract(vo.getOpenAvgPrice()))
							.multiply(vo.getNowNum())
					);
				} else {
					vo.setFloatProfit(
							(vo.getOpenAvgPrice().subtract(new BigDecimal(markPrice.toString())))
									.multiply(vo.getNowNum())
					);
				}
			}
			utils.setScaleBySymbol(vo,vo.getSymbolName());
			voList.add(vo);
		}
		Page<ContractPositionPageVO> voPage = new Page<>();
		BeanUtils.copyProperties(pageList,voPage);
		voPage.setRecords(voList);
		// 表尾统计数据
		ContractPositionPageVO vo = new ContractPositionPageVO();
		vo.setNowNum(BigDecimal.ZERO);
		vo.setFloatProfit(BigDecimal.ZERO);
		vo.setHandlingFee(BigDecimal.ZERO);
		vo.setMargin(BigDecimal.ZERO);
		List<ContractPosition> one = contractPositionService.getBaseMapper().selectList(
				query
		);
		one.forEach(e -> {
			// 标记价
			String markRedisKey = e.getSymbolName() + "_mark_price";
			Object markPrice = redis.opsForValue().get(markRedisKey);
			BigDecimal floatProfit = BigDecimal.ZERO;
			if (markPrice != null) {
				// 做多做空未实现营口
				if (e.getSide().equals(ContractOrderEnum.Side.MORE.getName())) {
					floatProfit = (new BigDecimal(markPrice.toString()).subtract(e.getOpenAvgPrice()))
							.multiply(e.getNowNum());
				} else {
					floatProfit = (e.getOpenAvgPrice().subtract(new BigDecimal(markPrice.toString())))
							.multiply(e.getNowNum());
				}
			}
			vo.setNowNum(vo.getNowNum().add(e.getNowNum()));
			vo.setFloatProfit(vo.getFloatProfit().add(floatProfit));
			vo.setHandlingFee(vo.getHandlingFee().add(e.getHandlingFee()));
			vo.setMargin(vo.getMargin().add(e.getHandlingFee()));
		});
		ContractStatisticsBO<ContractPositionPageVO> bo = new ContractStatisticsBO<>();
		bo.setPage(voPage);
		bo.setStatistics(vo);
		return R.ok(bo);
	}


	/**
	 * 通过id查询仓位表
	 *
	 * @param id id
	 * @return R
	 */
	@ApiOperation(value = "通过id查询", notes = "通过id查询")
	@GetMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_view')")
	public R getById(@PathVariable("id") Long id) {
		return R.ok(contractPositionService.getById(id));
	}

	/**
	 * 新增仓位表
	 *
	 * @param contractPosition 仓位表
	 * @return R
	 */
	@ApiOperation(value = "新增仓位表", notes = "新增仓位表")
	@SysLog("新增仓位表")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('contract_contractposition_add')")
	public R save(@RequestBody ContractPosition contractPosition) {
		return R.ok(contractPositionService.save(contractPosition));
	}

	/**
	 * 修改仓位表
	 *
	 * @param contractPosition 仓位表
	 * @return R
	 */
	@ApiOperation(value = "修改仓位表", notes = "修改仓位表")
	@SysLog("修改仓位表")
	@PutMapping
	@PreAuthorize("@pms.hasPermission('contract_contractposition_edit')")
	public R updateById(@RequestBody ContractPosition contractPosition) {
		return R.ok(contractPositionService.updateById(contractPosition));
	}

	/**
	 * 通过id删除仓位表
	 *
	 * @param id id
	 * @return R
	 */
	@ApiOperation(value = "通过id删除仓位表", notes = "通过id删除仓位表")
	@SysLog("通过id删除仓位表")
	@DeleteMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_del')")
	public R removeById(@PathVariable Long id) {
		return R.ok(contractPositionService.removeById(id));
	}


	/**
	 * 导出excel 表格
	 *
	 * @param contractPosition 查询条件
	 * @return excel 文件流
	 */
	@ResponseExcel
	@GetMapping("/export")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_export')")
	public List<ContractPosition> export(ContractPosition contractPosition) {
		return contractPositionService.list(Wrappers.query(contractPosition));
	}

	/**
	 * 获取多宝比
	 *
	 * @return
	 */
	@ApiOperation(value = "分页查询", notes = "分页查询")
	@GetMapping("/proportion")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_view')")
	public R getProportion() {
		return R.ok(contractPositionService.getProportion());
	}

	/**
	 * 获取盈利榜前一百名
	 *
	 * @param page 分页对象
	 * @return
	 */
	@ApiOperation(value = "获取盈利榜前一百名", notes = "获取盈利榜前一百名")
	@GetMapping("/profit/ranking")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_view')")
	public R getProfitRanking(Page page) {
		IPage<ContractRankingVO> ranking = contractPositionService.getProfitRanking(page);
		long pages = ranking.getPages();
		long size = ranking.getSize();
		long seq = (pages == 0 ? 0 : pages - 1) * size;
		List<ContractRankingVO> records = ranking.getRecords();
		for (ContractRankingVO record : records) {
			seq++;
			record.setSeq(seq);
		}
		return R.ok(ranking);
	}

	/**
	 * 获取亏损榜前一百名
	 *
	 * @param page 分页对象
	 * @return
	 */
	@ApiOperation(value = "获取亏损榜前一百名", notes = "获取亏损榜前一百名")
	@GetMapping("/loss/ranking")
	@PreAuthorize("@pms.hasPermission('contract_contractposition_view')")
	public R getLossRanking(Page page) {
		IPage<ContractRankingVO> ranking = contractPositionService.getLossRanking(page);
		long pages = ranking.getPages();
		long size = ranking.getSize();
		long seq = (pages == 0 ? 0 : pages - 1) * size;
		for (ContractRankingVO record : ranking.getRecords()) {
			seq++;
			record.setSeq(seq);
			record.setProfitSum(CommonUtil.setUSDTScale(record.getProfitSum()));
		}
		return R.ok(ranking);
	}

	/**
	 * 获取当前 持仓量+持仓人数
	 *
	 * @param type 不为空则查汇总，为空则查询各个币对
	 * @return
	 */
	@ApiOperation(value = "获取当前 持仓量+持仓人数", notes = "获取当前 持仓量+持仓人数")
	@GetMapping("/statistics/{type}")
	public R<List<ContractPositionStatisticsWebVO>> getPositionStatistics(@PathVariable("type") String type) {
		try {
			List<ContractSymbolMongo> one = mongo.find(new Query(), ContractSymbolMongo.class);
			if ("all".equals(type)) {
				ContractPositionStatisticsWebVO webVO = new ContractPositionStatisticsWebVO();
				webVO.setEmptyCount(0);
				webVO.setMoreCount(0);
				webVO.setMoreNum(new BigDecimal("0"));
				webVO.setEmptyNum(new BigDecimal("0"));
				for (ContractSymbolMongo symbolMongo : one) {
					if (symbolMongo.getEmptyNum() != null) {
						webVO.setEmptyNum(webVO.getEmptyNum().add(symbolMongo.getEmptyNum()));
					}
					if (symbolMongo.getMoreNum() != null) {
						webVO.setMoreNum(webVO.getMoreNum().add(symbolMongo.getMoreNum()));
					}
					if (symbolMongo.getMoreCount() != null) {
						webVO.setMoreCount(webVO.getMoreCount() + symbolMongo.getMoreCount());
					}
					if (symbolMongo.getEmptyCount() != null) {
						webVO.setEmptyCount(webVO.getEmptyCount() + symbolMongo.getEmptyCount());
					}
				}
				return R.ok(new ArrayList<ContractPositionStatisticsWebVO>(){{
					webVO.setEmptyNum(webVO.getEmptyNum().setScale(3, RoundingMode.HALF_UP));
					webVO.setMoreNum(webVO.getMoreNum().setScale(3, RoundingMode.HALF_UP));
					add(webVO);
				}});
			} else {
				ArrayList<ContractPositionStatisticsWebVO> webVOS = new ArrayList<>();
				for (ContractSymbolMongo symbolMongo : one) {
					ContractPositionStatisticsWebVO vo = new ContractPositionStatisticsWebVO();
					BeanUtils.copyProperties(symbolMongo,vo);
					vo.setName(symbolMongo.getName());
					utils.setScaleBySymbol(vo,vo.getName());
					webVOS.add(vo);
				}
				return R.ok(webVOS);
			}
		} catch (Exception e) {
			return R.failed("查询失败");
		}
	}

	/**
	 * 根据用户id获取用户总盈亏
	 * @param id 用户id
	 * @return 盈亏
	 */
	@GetMapping("/profit/{id}")
	public R<BigDecimal> getUserProfit(@PathVariable("id") Long id) {
		try {
			BigDecimal profit = positionMapper.getUserProfit(id);
			if (profit != null) {
				return R.ok(profit.setScale(2,BigDecimal.ROUND_DOWN));
			}
			return R.ok();
		} catch (Exception e) {
			e.printStackTrace();
			return R.failed("查询错误");
		}
	}
}
